#include "userfunc.h"
#include <QString>
#include <QVariant>
#include <QDateTime>
#include <QFileDialog>
#include <QFile>
#include <QMessageBox>
#include <QTextStream>

UserFunc::UserFunc(QList<QObject *> object,QObject *parent)
    : QObject{parent}, obj(object)
{
    // 实例化串口类
    serial_main = new Serial();
    // 实例化网络类
    network_main = new network();
    // 定义文本编码
    tc = QTextCodec::codecForName("UTF-8");
    // 初始化时串口扫描一次
    this->serialNameList = serial_main->serialScan();
    // 设置端口号下拉内容
    this->set_QMLproperty(1);
    // 设置串口描述信息
    this->set_QMLproperty(3);
    // 定时发送
    t1 = new QTimer(this);
    connect(t1, &QTimer::timeout, this, [=](){
        this->set_sendDate(this->pageIndex, this->get_QMLproperty(3).toString(), this->get_QMLproperty(4).toInt(), this->get_QMLproperty(5).toString());
    });
    // 实例化串口事件
    mySerialEvent = new SerialEvent();
    // 串口插入处理
    connect(mySerialEvent, &SerialEvent::comDevArriaval, this , [=](){
        this->serialNameList = serial_main->serialScan(); // 扫描串口
    });
    // 串口拔出处理
    connect(mySerialEvent, &SerialEvent::comDevRemoveComplete, this , [=](QString devName){
        serialNameList = serial_main->serialScan(); // 扫描串口
        // 当前端口号选择是否是拔出的
        if(this->get_QMLproperty(1).toString() == devName)
        {
            // 是否打开串口
            if(this->get_QMLproperty(2).toBool())
            {
                this->set_QMLproperty(2);
                serial_main->close();
                this->set_QMLproperty(1); // 更新端口号下拉选项
                QMessageBox::about(NULL, warningTitle_serial, "<font size=\"4\">当前串口已关闭</font>");
            }
            else
            {
                this->set_QMLproperty(1); // 更新端口号下拉选项
            }
        }
    });
    shortcut_data_get();
}
// 发送数据
void UserFunc::set_sendDate(unsigned char who, QString transmitData, char suffixIndex, QString txCode)
{
    QByteArray transmitDataTemp;
    QString suffixTemp;
    suffixTemp = this->suffixHandle(suffixIndex);
    if(txCode == "ASCII") {
        // 将获取的文本内容转换为QByteArray类型
        transmitDataTemp = tc->fromUnicode(transmitData.append(suffixTemp));
    } else if(txCode == "HEX") {
        // 将获取的文本内容转换为QByteArray类型后再转换为16进制并大写
        transmitDataTemp = QByteArray::fromHex(tc->fromUnicode(transmitData.append(suffixTemp))).toUpper();
    }
    this->sendDataBuf = transmitDataTemp;
    switch(who)
    {
        case 1: serial_main->sendData(transmitDataTemp); break;
        case 2: network_main->TCPClient_sendData(transmitDataTemp); break;
        case 3: network_main->TCPServer_sendData(transmitDataTemp); break;
        case 4: network_main->UDP_sendData(transmitDataTemp); break;
    }
}
// 获取数据
QString UserFunc::get_recData(unsigned char who, QString rxCode, bool dateBtn)
{
    QString dataTemp;
    QByteArray byteArrayTemp;
    switch(who)
    {
        case 1: byteArrayTemp = serial_main->dataBuf; break;
        case 2: byteArrayTemp = network_main->TCPClient_dataBuf; break;
        case 3: byteArrayTemp = network_main->TCPServer_dataBuf; break;
        case 4: byteArrayTemp = network_main->UDP_dataBuf; break;
    }
    if(dateBtn) // 时间戳
    {
        dataTemp.append(this->getCurrentTime());
    }
    if(rxCode == "ASCII")
    {
        dataTemp.append(tc->toUnicode(byteArrayTemp));
    }
    else if(rxCode == "HEX")
    {
        dataTemp.append(QString(byteArrayTemp.toHex(' ')).toUpper()).append(" ");
    }
    if(dateBtn) // 时间戳需要换行
    {
        dataTemp.append("<br>");
    }
    // 替换\n为<br> 以达到换行效果
    dataTemp.replace("\n", "<br>");
    dataTemp.replace("\r", "<br>");
    return dataTemp;
}
// 获取发送数据 用于数据回显 显示为白色
QString UserFunc::get_sendData(QString rxCode, bool dateBtn)
{
    QString stringTemp;
    if(dateBtn) // 时间戳
    {
        stringTemp.append(this->getCurrentTime());
    }
    stringTemp.append("<font color=\"#ffffff\">");
    if(rxCode == "ASCII")
    {
        stringTemp.append(tc->toUnicode(this->sendDataBuf));
    }
    else if(rxCode == "HEX")
    {
        stringTemp.append(QString(this->sendDataBuf.toHex(' ')).toUpper()).append(" ");
    }
    stringTemp.append("</font>");
    if(dateBtn) // 时间戳
    {
        stringTemp.append("<br>");
    }
    // 替换\n为<br> 以达到换行效果
    stringTemp.replace("\n", "<br>");
    stringTemp.replace("\r", "<br>");
    return stringTemp;
}

// 串口开关点击处理
void UserFunc::on_serial_switch_clicked(bool serial_switch, QString serial_name, QString serial_boud)
{
    // 判断串口开关状态
    if(serial_switch)
    {
        // 判断是否能够打开串口 打不开则报错
        if(serial_main->serialOpen(serial_name, serial_boud.toInt()))
        {
        }
        else
        {
            this->set_QMLproperty(2);
            QMessageBox::about(NULL, warningTitle_serial, "<font size=\"4\">未选择串口或当前串口无法打开</font>");
        }
    }
    else
    {
        // 关闭串口
        serial_main->serialClose();
    }
}
// 获取串口描述信息
QString UserFunc::get_serialDescription(unsigned char desIndex)
{
    return serial_main->serialDescription.at(desIndex);
}
// 获取当前时间 显示为橙色
QString UserFunc::getCurrentTime(void)
{
    return QString("<font color=\"#ee9900\">%1</font>").arg(QDateTime::currentDateTime().toString("[hh:mm:ss.zzz]"));
}
// 数据后缀处理
QString UserFunc::suffixHandle(unsigned char index)
{
    QString suffixTemp;
    switch(index)
    {
        case 0: suffixTemp = ""; break;
        case 1: suffixTemp = "\r"; break;
        case 2: suffixTemp = "\n"; break;
        case 3: suffixTemp = "\r\n"; break;
        case 4: suffixTemp = "\n\r"; break;
    }
    return suffixTemp;
}
// 设置QML属性
void UserFunc::set_QMLproperty(unsigned char propertyIndex)
{
    auto window = qobject_cast<QObject*>(this->obj.front());
    switch(propertyIndex)
    {
        case 1: // 更新端口号复选框下拉选项
            window->findChild<QObject*>("serial_name")->setProperty("model", QVariant(this->serialNameList));
        break;
        case 2: // 设置串口开关状态为false
            window->findChild<QObject*>("serial_switch")->setProperty("checked", QVariant("false"));
        break;
        case 3: // 设置串口描述信息
            window->findChild<QObject*>("serial_description")->setProperty("text", QVariant(serial_main->serialDescription.at(0)));
        break;
        case 4: // 设置快捷方式右侧侧边栏内容
            window->findChild<QObject*>("shortcut_CtrlText1")->setProperty("text", QVariant(this->shortcutDataList.at(0)));
            window->findChild<QObject*>("shortcut_CtrlText2")->setProperty("text", QVariant(this->shortcutDataList.at(1)));
            window->findChild<QObject*>("shortcut_CtrlText3")->setProperty("text", QVariant(this->shortcutDataList.at(2)));
            window->findChild<QObject*>("shortcut_CtrlText4")->setProperty("text", QVariant(this->shortcutDataList.at(3)));
            window->findChild<QObject*>("shortcut_CtrlText5")->setProperty("text", QVariant(this->shortcutDataList.at(4)));
            window->findChild<QObject*>("shortcut_AltText1")->setProperty("text", QVariant(this->shortcutDataList.at(5)));
            window->findChild<QObject*>("shortcut_AltText2")->setProperty("text", QVariant(this->shortcutDataList.at(6)));
            window->findChild<QObject*>("shortcut_AltText3")->setProperty("text", QVariant(this->shortcutDataList.at(7)));
            window->findChild<QObject*>("shortcut_AltText4")->setProperty("text", QVariant(this->shortcutDataList.at(8)));
            window->findChild<QObject*>("shortcut_AltText5")->setProperty("text", QVariant(this->shortcutDataList.at(9)));
            window->findChild<QObject*>("shortcut_Texta")->setProperty("text", QVariant(this->shortcutDataList.at(10)));
            window->findChild<QObject*>("shortcut_Textb")->setProperty("text", QVariant(this->shortcutDataList.at(11)));
            window->findChild<QObject*>("shortcut_Textc")->setProperty("text", QVariant(this->shortcutDataList.at(12)));
            window->findChild<QObject*>("shortcut_Textd")->setProperty("text", QVariant(this->shortcutDataList.at(13)));
            window->findChild<QObject*>("shortcut_Texte")->setProperty("text", QVariant(this->shortcutDataList.at(14)));
            window->findChild<QObject*>("shortcut_Textf")->setProperty("text", QVariant(this->shortcutDataList.at(15)));
            window->findChild<QObject*>("shortcut_Textg")->setProperty("text", QVariant(this->shortcutDataList.at(16)));
            window->findChild<QObject*>("shortcut_Texth")->setProperty("text", QVariant(this->shortcutDataList.at(17)));
            window->findChild<QObject*>("shortcut_Texti")->setProperty("text", QVariant(this->shortcutDataList.at(18)));
        break;
    }
}
// 获取QML属性
QVariant UserFunc::get_QMLproperty(unsigned char propertyIndex)
{
    auto window = qobject_cast<QObject*>(this->obj.front());
    QVariant variantTemp;
    switch(propertyIndex)
    {
        case 1: // 获取端口复选框当前内容
            variantTemp = window->findChild<QObject*>("serial_name")->property("displayText");
        break;
        case 2: // 获取串口开关状态
            variantTemp = window->findChild<QObject*>("serial_switch")->property("checked");
        break;
        case 3: // 获取发送框内容
            variantTemp = window->findChild<QObject*>("sendData")->property("text");
        break;
        case 4: // 获取后缀索引
            variantTemp = window->findChild<QObject*>("txSuffix")->property("currentIndex");
        break;
        case 5: // 获取接收编码
            variantTemp = window->findChild<QObject*>("txCode")->property("text");
        break;
    }
    return variantTemp;
}
// 自动发送按键点击
void UserFunc::on_autoSend_clicked(bool autoBtn, QString autoTime)
{
    if(autoBtn)
    {
        if(autoTime.toInt() > 0)
        {
            t1->start(autoTime.toInt()); // 将键入框内的数据给定时器
        }
    }
    else
    {
        t1->stop();
    }
}
// 保存至文件按键点击
void UserFunc::on_save_file_clicked(QString serialData)
{
    QString filename = QFileDialog::getSaveFileName(NULL,tr("保存文件"),"",tr("*.txt;;")); //选择路径
    if(filename.isEmpty())
    {
        return;
    }
    else
    {
        QFile *file = new QFile(filename);//此路径下没有就会自己创建一个
        if(!file->open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) {
           QMessageBox::about(NULL, warningTitle_serial, "<font size=\"4\">文件保存错误, 请重新保存</font>");
           return;
        }
        QTextStream in(file);
        in << serialData;
        file->close();
    }
}
// 获取端口号列表
QVariant UserFunc::get_serialName()
{
    return QVariant(this->serialNameList);
}
// 获取接收/发送字节数
int UserFunc::get_RxTxByte(int who)
{
    int byteTemp = 0;
    switch(who)
    {
        case 1: byteTemp = serial_main->rxByte; break;
        case 2: byteTemp = serial_main->txByte; break;
        case 3: byteTemp = network_main->TCPClient_rxByte; break;
        case 4: byteTemp = network_main->TCPClient_txByte; break;
        case 5: byteTemp = network_main->TCPServer_rxByte; break;
        case 6: byteTemp = network_main->TCPServer_txByte; break;
        case 7: byteTemp = network_main->UDP_rxByte; break;
        case 8: byteTemp = network_main->UDP_txByte; break;
    }
    return byteTemp;
}
// 清零接收/发送字节数
void UserFunc::clear_RxTxByte(int who)
{
    switch(who)
    {
        case 1: serial_main->rxByte = 0; break;
        case 2: serial_main->txByte = 0; break;
        case 3: network_main->TCPClient_rxByte = 0; break;
        case 4: network_main->TCPClient_txByte = 0; break;
        case 5: network_main->TCPServer_rxByte = 0; break;
        case 6: network_main->TCPServer_txByte = 0; break;
        case 7: network_main->UDP_rxByte = 0; break;
        case 8: network_main->UDP_txByte = 0; break;
    }
}
// 获取页面标志
unsigned char UserFunc::get_pageIndex()
{
    return this->pageIndex;
}
// 设置页面标志
void UserFunc::set_pageIndex(unsigned char index)
{
    this->pageIndex = index;
}
// 设置QML源对象
void UserFunc::set_QMLObject(QList<QObject *> object)
{
    this->obj = object;
}

// 网络开关按键点击处理
void UserFunc::on_ipSwitch_clicked(bool ipSwitch, QString ownIp, unsigned short ownPort, QString remoteIp, unsigned short remotePort)
{
    bool openResult = true;
    if(ipSwitch)
    {
        switch(this->pageIndex)
        {
            case 2: openResult = network_main->TCPClient_open(remoteIp, remotePort); break;
            case 3: openResult = network_main->TCPServer_open(ownIp, ownPort); break;
            case 4: openResult = network_main->UDP_open(ownIp, ownPort, remoteIp, remotePort); break;
        }
    }
    else
    {
        switch(this->pageIndex)
        {
            case 2: network_main->TCPClient_close(); break;
            case 3: network_main->TCPServer_close(); break;
            case 4: network_main->UDP_close(); break;
        }
    }
    if(!openResult)
    {
        QMessageBox::about(NULL, warningTitle_ip, "<font size=\"4\">网络服务建立失败, 请检查参数</font>");
    }
}

// 右侧快捷方式侧边栏内容保存
void UserFunc::shortcut_data_save(int shortcutNum, QString shortcutData)
{
    QFile *file = new QFile("./userFiles/shortcutData.txt");//此路径下没有就会自己创建一个
    if(!file->open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) {
       QMessageBox::about(NULL,"文件错误","快捷方式内容存储文件打开错误, 请检查根目录userFiles/shortcutData.txt文件");
       return;
    }
    QTextStream file_in(file);
    QString dataTemp = "";
    dataTemp = shortcutData.append("^##^");
    this->shortcutDataList.removeAt(shortcutNum - 1);
    this->shortcutDataList.insert(shortcutNum - 1, dataTemp);
    file_in << this->shortcutDataList.join("");
    file->close();
}
void UserFunc::shortcut_data_get(void)
{
    QFile *file = new QFile("./userFiles/shortcutData.txt");//此路径下没有就会自己创建一个
    if(!file->open(QIODevice::ReadOnly | QIODevice::Text)) {
       QMessageBox::about(NULL,"文件错误","快捷方式内容存储文件打开错误, 请检查根目录userFiles/shortcutData.txt文件");
       return;
    }
    QTextStream filein(file);
    QString sss = "";
    sss = filein.readAll();
    file->close();
    this->shortcutDataList = sss.split("^##^"); // 分割出内容
    this->shortcutDataList.removeLast(); // 删除最后一个空白
    this->set_QMLproperty(4);
    QStringList dataListTemp;
    for(char i = 0; i < this->shortcutDataList.count(); i++)
    {
        dataListTemp.append(QString(this->shortcutDataList.at(i)).append("^##^")); // 重组并添加后缀
    }
    this->shortcutDataList = dataListTemp;
}
/******************************************data************************************************/
// 数据操作相关处理函数
QString UserFunc::on_deleteBtn1_clicked(QString originData, QString targetData1, QString targetData2)
{
    qDebug() << originData << targetData1 << targetData2;
    QString resultText = originData.replace(targetData1, QString("<font color=\"#ff0000\">%1</font>").arg(targetData2)); // 替换
    resultText = resultText.replace("\n", "<br>"); // /n在html标签内不换行，故换成html的换行标签解决此问题
    resultText.append(" "); // 解决文本尾部变色后仍有一个新增字符会与其同色的bug
    return resultText;
}

QString UserFunc::on_deleteBtn2_clicked(QString originData, QString targetData1, QString targetData2)
{
    qDebug() << originData << targetData1 << targetData2;
    QString resultText;
    if(targetData1.contains("---",Qt::CaseInsensitive))
    {
        QStringList deleteData = targetData1.split("---"); // 按照x---y格式将数据分割
        resultText = originData.replace(QString(deleteData.at(1)), QString(deleteData.at(0))); // 把目标数据中的y替换为x
        QStringList resultList = resultText.split(QString(deleteData.at(0))); // 以x分割数据
        resultText.clear();
        // 遍历字符串列表
        for(int i = 0; i < resultList.count(); i++)
        {
            // 将偶数数据组合(含0)
            if(i % 2 == 0)
            {
                resultText.append(resultList.at(i));
            } // 将奇数数据替换
            else
            {
                resultText.append(QString("<font color=\"#ff0000\">%1</font>").arg(targetData2));
            }
        }
        resultText = resultText.replace("\n", "<br>"); // /n在html标签内不换行，故换成html的换行标签解决此问题
    }
    else
    {
        resultText.clear();
        QMessageBox::about(NULL, warningTitle_data, "<font size=\"4\">请按照x---y的格式<br>例如:<br>目标数据:123(xx)456<br>需要替换(xx)<br>则输入(---)</font>");
        return originData;
    }
    return resultText;
}

QVariant UserFunc::on_findBtn1_clicked(QString originData, QString targetData1)
{
    qDebug() << originData << targetData1;
    // 查找数据变色原理是将其添加html标签设置颜色
    /***********************方法一**************************/
    QString replaceText = QString("<font color=\"#ffff00\">%1</font>").arg(targetData1); // 替换为的数据
    QString resultText = originData.replace(targetData1, replaceText); // 替换
    resultText = resultText.replace("\n", "<br>"); // /n在html标签内不换行，故换成html的换行标签解决此问题
    resultText.append(" "); // 解决文本尾部变色后仍有一个新增字符会与其同色的bug
    return QVariant(resultText);
    /***********************方法二**************************/
//    QStringList originList = ui->dataTemp->toPlainText().split("\n"); // 将每行数据拆分放入QStringList
//    QString searchText = ui->deleteData->toPlainText(); // 要替换的数据
//    originList.replaceInStrings(searchText, "<font color=\"#ff0000\">" + searchText + "</font>"); // 替换
//    QString resultText = originList.join("<br>"); // /n由于未知原因不换行，故换成html的换行标签解决此问题
//    ui->dataTemp->setText(resultText);
}

QString UserFunc::on_findBtn2_clicked(QString originData, QString targetData1)
{
    qDebug() << originData << targetData1;
    QString resultText;
    if(targetData1.contains("---",Qt::CaseInsensitive))
    {
        QStringList deleteData = targetData1.split("---"); // 按照x---y格式将数据分割
        resultText = originData.replace(QString(deleteData.at(1)), QString(deleteData.at(0))); // 把目标数据中的y替换为x
        QStringList resultList = resultText.split(QString(deleteData.at(0))); // 以x分割数据
        resultText.clear();
        // 遍历字符串列表
        for(int i = 0; i < resultList.count(); i++)
        {
            // 将偶数数据组合(含0)
            if(i % 2 == 0)
            {
                resultText.append(resultList.at(i));
            } // 将奇数数据与x y重新组合并添加html标签变色
            else
            {
                resultText.append(QString("<font color=\"#ffff00\">%1%2%3</font>").arg(deleteData.at(0)).arg(resultList.at(i)).arg(deleteData.at(1)));
            }
        }
        resultText = resultText.replace("\n", "<br>"); // /n在html标签内不换行，故换成html的换行标签解决此问题
    }
    else
    {
        resultText.clear();
        QMessageBox::about(NULL, warningTitle_data, "<font size=\"4\">请按照x---y的格式<br>例如:<br>目标数据:456#xx#123<br>需要查找#xx#<br>则输入#---#</font>");
        return originData;
    }
    return resultText;
}

QString UserFunc::on_changeBtn_clicked(QString originData, int codeComboIndex)
{
    QByteArray dataTempToByteArray;
    QString resultText;
    switch(codeComboIndex)
    {
        case 1: // HEX
            dataTempToByteArray = tc->fromUnicode(originData);
            resultText = dataTempToByteArray.toHex(' ').toUpper().append(" ");
            break;
        case 0: // UTF8
            dataTempToByteArray = QByteArray::fromHex(tc->fromUnicode(originData).toUpper());
            resultText = tc->toUnicode(dataTempToByteArray).toUtf8();
            break;
    }
    return resultText;
}

void UserFunc::on_originData_textChanged(QString originData)
{
    this->enBytes = originData.length(); // 英文字节数
    this->zh_cnBytes = originData.toLocal8Bit().length(); // 中文字节数
}

int UserFunc::get_enBytes()
{
    return this->enBytes;
}

int UserFunc::get_zh_cnBytes()
{
    return this->zh_cnBytes;
}

void UserFunc::on_targetTitle1_clicked()
{
    QMessageBox::about(NULL, aboutTitle_data, "<font size=\"4\">此处填写需要替换或查找的数据(替换为空即删除数据)<br>执行范围替换的填写格式请点击[范围替换]按钮查看</font>");
}

void UserFunc::on_targetTitle2_clicked()
{
    QMessageBox::about(NULL, aboutTitle_data, "<font size=\"4\">此处填写需要替换为的数据</font>");
}

void UserFunc::on_originTitle_clicked()
{
    QMessageBox::about(NULL, aboutTitle_data, "<font size=\"4\">此处填写需要被操作的目标数据<br>绿色为目标源数据<br>红色是替换的数据<br>黄色是查找的数据</font>");
}



